/*
 * Copyright 2006 Brian Watkins
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package bw.util;

import java.util.*;

/**
 * A blocking Queue; good for implementing a producer/consumer model where
 * one thread (producer) is putting items in the queue, and another thread
 * (consumer) is taking them out and doing something with them.
 */

public class BlockingQue
{
    protected AbstractList _list = null;

    public BlockingQue ()
    {
        _list = new ArrayList();
    }
    
    public BlockingQue ( AbstractList list )
    {
        //subclasses can use this constructor
        //to provide their own implementation
        _list = list;
    }

    public void add ( Object item )
    {
        synchronized ( _list ) 
        {
            _list.add( item );
            _list.notify();
        }
    }

    public Object remove ( long millisToWait )
    {
        Object obj = null;

        //note -- must synchronize on _list -- _list.wait() will remove the
        //synchronization lock allowing the add method above to work while we wait
        //for someone to add an object
        synchronized ( _list ) 
        {
            if ( _list.isEmpty() ) 
            {
                try 
                {
                    //block for a bit
                    _list.wait( millisToWait );
                }
                catch ( InterruptedException e ) 
                {
                    //we were interrupted by some other thread while waiting for an object
                    //probably during shutdown of someone who uses this que
                }
            }

            //check again because we could either get here if a new object has
            //been added or if we waited long enough (and the list is still empty)
            //or we were interrupted by another thread (and the list is still empty)
            if ( !_list.isEmpty() )
            {
                obj = _list.remove( 0 );
            }
        }

        return obj;
    }

    public Object remove()
    {
        //waits forever -- convenience
        return remove( 0 );
    }

    public int size() 
    { 
        return _list.size(); 
    }

    public void flush()
    {
        _list.clear();
    }

    public boolean isEmpty()
    {
        return _list.isEmpty();
    }

    public boolean contains ( Object obj )
    {
        return _list.contains( obj );
    }

}

